#!/usr/bin/env python

"""Test show how is elected a leader in a n-cycle graph.
Usage: python leader_election.py [n]"""

import logging
import sys

import nxchaos as nxc

#_______________________________________________________________________________

NODES = 10
nxc.setup_log('debug')
_logger = logging.getLogger('nxchaos.test')

#_______________________________________________________________________________

class LeaderElection(nxc.algorithm.IAlgorithm):

    def run(self):
        
        i_am_the_leader = False

        self.send(1, self.id_random)
        yield

        while True:
            _logger.debug("[id random:{id_random}, inbox:{inbox}".format(id_random=self.id_random, inbox=self.inbox))

            for port, message in self.inbox:
                 # if port is 0 then send to port nr 1; if 1 then to 0
                forward = ~ port % 2

                if message == "elected": # must be first - integer and string comparison is allowed
                    if i_am_the_leader == False:
                        self.send(forward, "elected")

                        # no idea how to show what can be stored in this algorithm
                        if self.get_data() is None:
                            self.save_data([port, message])

                    else:
                        _logger.info("All nodes informed.")

                    return # stop the algorithm

                elif message > self.id_random:
                    self.send(forward, message)
            
                elif message == self.id_random:
                    _logger.info("[id_random:{id_random}] I'm the leader.".format(id_random=self.id_random))
                    i_am_the_leader = True
                    self.send(forward, "elected")

            yield

#_______________________________________________________________________________

if __name__ == "__main__":

    if len(sys.argv) > 1:
        NODES = int(sys.argv[1])

    _logger.info("Nodes in a graph: {0}".format(NODES))

    gfactory = nxc.graph.GraphFactory()
    graph = gfactory.from_builtin("cycle", n=NODES)
    #graph = gfactory.from_adjlist("temp.txt")

    _logger.info("Rendering graph.")
    nxc.util.render_picture(graph)
    nxc.util.render_text(graph)

    network = nxc.network.Network(graph, LeaderElection)

    # algorithm ends in 2 * NODES rounds, so let's try to work more (3 * NODES)

    # ============ first approach ============
    
    _logger.info("\n\n============ first approach ============\n")

    network.prepare()
    network.work_n_rounds(3 * NODES)


    # ============ second approach ===========

    _logger.info("\n\n============ second approach ===========\n")

    network.prepare()

    for i in range(3 * NODES):
        _logger.info("Round nr {0}".format(i))

        try:
            network.round()

        except StopIteration as err:
            _logger.info(str(err))
            break

    # ============ third approach ============

    _logger.info("\n\n============ third approach ============\n")

    network.save_partial_data(True)
    network.prepare()

    i = 0
    while network.is_working():
        _logger.info("Round nr {0}".format(i))
        network.round()
        i += 1

    _logger.info("Saved data:")
    for worker in network:
        _logger.info("id:{0}, data:{1}".format(worker.id_random, worker.get_data()))

    _logger.info("Saving calculated data to file...")
    network.save_data()

    str_diffList = "Comparing results - diff list:\n"
    comparison, diffList = nxc.util.compare_results('result1.txt', 'result2.txt')
    for line in diffList:
        str_diffList += line

    _logger.info(str_diffList)
    _logger.info("Comparison result: {0}".format(comparison))
